home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / os2xlisp.zip / TEMP.DOC < prev    next >
Text File  |  1988-06-13  |  19KB  |  468 lines

  1.                                                 Andrew Schulman
  2.                                                 32 Andrews St. #2
  3.                                                 Cambridge MA 02139
  4.  
  5.                                                 (617) 876-2102 (h)
  6.                                                 (617) 576-6920 (w)
  7.  
  8.                                                 13 June 1988
  9.  
  10.  
  11. TEMP.DOC -- shortened documentation for OS2XLISP v. 1.10
  12.  
  13.     OS2XLISP is a Lisp interpreter for the OS/2 operating system.  It has
  14. many special features to facilitate exploration of the OS/2 API and of
  15. protected mode.  Version 1.10 has many improvements over 1.0, including:
  16.  
  17.         -- ability to call the C run-time library from Lisp programs
  18.         -- (getprocaddr) for DOSCALLS no longer requires ordinal numbers
  19.         -- (call) now works for non-Microsoft dynamic link libraries
  20.         -- structures: conversion between OS/2 structures and Lisp lists
  21.         -- better protection again GP faults
  22.         -- now runs even if stdin/stdout have been redirected
  23.         -- improved interface to (peek) and (poke)
  24.         -- macro character ^ as shorthand for (addr)
  25.         -- ability to enumerate procedures in a dynamic-link library
  26.         -- the prompt is user-definable
  27.  
  28.     The following is shortened, non-user-friendly (user-hostile?)
  29. documentation.  Complete documentation is available in the file OXLDOC.ARC
  30. which should be available mid June.
  31.  
  32.  
  33. 1)  *** THE FILES ***
  34.  
  35.     OXLEXE.ARC contains the executable file, dynamic-link library,
  36. initialization files, shortened documentation, and one sample program
  37. for OS2XLISP version 1.1.  The component files are:
  38.  
  39.         OS2XLISP.EXE -- executable            
  40.             (OS2XLISP.EXE    117586  12 Jun 88  10:19a)
  41.         CRTLIB.DLL -- dynamic-link library
  42.             (CRTLIB.DLL       89310  22 Apr 88   8:03p)
  43.         INIT.LSP -- initialization file
  44.             (INIT.LSP          8328  13 Jun 88   6:09p)
  45.         STRUCT.LSP -- initialization file
  46.             (STRUCT.LSP        5262  13 Jun 88   6:17p)
  47.         BACH.LSP -- sample program
  48.         TEMP.DOC -- this file!
  49.  
  50.     The other ARC files that comprise OS2XLISP version 1.1 are:
  51.  
  52.         OXLSRC.ARC -- C and ASM source code
  53.         OXLDOC.ARC -- complete documentation
  54.         OXLLSP.ARC -- sample Lisp programs
  55.  
  56.  
  57. 2)  *** REQUIREMENTS ***
  58.  
  59.     As its name clearly implies, OS2XLISP requires the OS/2 operating
  60. system.  Versions of XLISP for MS-DOS, the Mac, the VAX, and so on, are
  61. available on CompuServe in the AI EXPORT forum (GO AIE), in the Lisp
  62. data library.
  63.  
  64.     Note that OS2XLISP is NOT a bound executable -- it requires OS/2
  65. protected mode.  It will not run in the 3.x compatibility box.
  66.  
  67.     The file CRTLIB.DLL must be in a directory named in the LIBPATH
  68. statement in your OS/2 CONFIG.SYS file.  Otherwise you will get:
  69.  
  70.         C:\OS2\XLISP>os2xlisp
  71.         SYS1804: The system cannot find the file CRTLIB.
  72.  
  73. This dynamic-link library contains the C run-time library used by
  74. OS2XLISP.  Also, please use the CRTLIB.DLL that came with OXLEXE.ARC --
  75. there may be other files called CRTLIB.DLL floating around.  The one
  76. you use should be 89K large.
  77.  
  78.     The two initialization files, INIT.LSP and STRUCT.LSP, should be
  79. in the directory from which you call OS2XLISP.  OS2XLISP will run, but
  80. will not behave very well, if it can't find when it starts up.
  81.  
  82.  
  83. 2a) *** ODDITIES OF THE DosPTrace FEATURE ***
  84.  
  85.     OS2XLISP by default uses the OS/2 function DosPTrace to "catch"
  86. GP faults.  This works very nicely, and helps make OS2XLISP a stable
  87. programming environment, but unfortunately only one invocation of
  88. DosPTrace can be active in OS/2 at any given time, and CodeView is
  89. built atop DosPTrace.
  90.  
  91.     If CodeView is running in another session, either shut down CodeView
  92. or invoke OS2XLISP with the -x flag:
  93.  
  94.         C:\OS2\XLISP>os2xlisp -x
  95.  
  96. Otherwise, you will get the message:
  97.  
  98.         PROTECT: Denied access to C:\OS2\XLISP\OS2XLISP.EXE
  99.  
  100.     For the same reason, if you want to run more than one concurrent
  101. "instance" of OS2XLISP at one time, every instance after the first will
  102. have to be invoked with the -x flag.  As you have gathered by now,
  103. the -x flag turns off the use of DosPTrace.
  104.  
  105.     On the other hand, if you want to see DosPTrace at work, invoke
  106. OS2XLISP with the -v flag.  Particularly educational if you deliberately
  107. try to crash OS2XLISP with something like:
  108.  
  109.         > (poke #xB8000000 666)
  110.  
  111.  
  112. 3)  *** GETTING STARTED ***
  113.  
  114.     By now you have gathered that to start OS2XLISP, you type its name
  115. at the OS/2 prompt (perhaps followed by the -x or -v flag):
  116.  
  117.         C:\OS2\XLISP>os2xlisp
  118.  
  119.     OS2XLISP will spew out some messages (there will be even more with
  120. the verbose -v flag!):
  121.  
  122.         XLISP version 2.0, Copyright (c) 1988, by David Betz
  123.         OS/2 protected-mode extensions vers. 1.10, (c) 1988,by Andrew Schulman
  124.         ; loading "init.lsp"
  125.         ; loading "STRUCT.lsp"
  126.         6/13/1988   20:5:2
  127.         >
  128.  
  129.     The ">" is the Lisp prompt.  OS2XLISP is waiting for an expression,
  130. which it will read and evaluate.  It will print the results of the evaluation.
  131. For instance:
  132.  
  133.         > (+ 2 3)
  134.         5
  135.  
  136.     Note Lisp's famous parentheses, which mark the begin and end of an
  137. expression.  Note that operators _precede_ operands.  Here's another example:
  138.  
  139.         > (define foo (+ 2 3))                  ; 1
  140.         5
  141.         > foo                                   ; 2
  142.         5
  143.         > (+ foo 10)                            ; 3
  144.         15
  145.         > (if (= 15 (+ foo 10))                 ; 4
  146.             "Okay!"
  147.           ; else
  148.             "Something is very wrong!")
  149.         "Okay!"
  150.             
  151.     As in assembly language, comments start with a semicolon ; and go
  152. to the end of the line.  In the above example, our input expressions have
  153. been commented so we can refer to them easily:
  154.  
  155.     1 -- define the variable FOO to be the sum of 2 and 3.  note how
  156.          expressions can be arbitarily nested inside expressions
  157.              
  158.     2 -- to query the value of a variable, just type its name (without
  159.          parentheses)
  160.              
  161.     3 -- variables can be used in expressions just as immediate values can.
  162.         
  163.     4 -- if the sum of FOO and 10 is equal to 15, return the string "Okay!"
  164.          Otherwise, return the string "Something is very wrong!"
  165.              
  166.     So far, we have been using Lisp as a glorified calculator -- we type
  167. in an expression, and OS2XLISP prints out the results.  We can also write
  168. Lisp programs in ASCII text files (using your favorite protected-mode
  169. editor -- I recommend Lugaru Software's Epsilon), and ask OS2XLISP to
  170. evaluate the program.  For instance, the two initialization files mentioned
  171. above -- INIT.LSP and STRUCT.LSP -- are just Lisp programs.  I suggest
  172. printing out these files.  But these are really just collections of useful
  173. routines, rather than programs.  This ARC contains one sample program,
  174. BACH.LSP.  To run this program:
  175.  
  176.         > (load 'bach)
  177.             
  178. or:
  179.  
  180.         > (load "c:\\os2\\xlisp\\bach.txt")     ; note double backslashes
  181.             
  182. or from the OS/2 command line:
  183.  
  184.         C:\OS2\XLISP>os2xlisp bach
  185.  
  186.     I have left the most important part to the end:  how to get out of
  187. OS2XLISP:
  188.  
  189.         > (exit)                ; quit back to operating system
  190.         C:\OS2\XLISP>rem we're back
  191.             
  192.     Note that hitting ^C or ^break will NOT get you back to OS/2:  instead,
  193. they will put you in the OS2XLISP debugger.  To get out of the debugger,
  194. hit ^Z a few times.
  195.  
  196.  
  197. 4)  *** AN OS/2 CALCULATOR:  RUN-TIME DYNAMIC LINKING ***
  198.  
  199.     While it's nice having a Lisp interpreter, you're probably most
  200. interested in how to interact with the OS/2 API from this
  201. interpreter.  Since a minute ago we used Lisp as a calculator,
  202. inputting some expressions and immediately printing out the results,
  203. you might be wondering: Can OS2XLISP can be used as an "OS/2
  204. calculator" to make some OS/2 function calls and print out their
  205. results, without having to write a "program"?  Yes ma'am!
  206.  
  207.         > (define vio-wrt-tty (getprocaddr viocalls "VIOWRTTTY"))   ; 1
  208.         15142831                                                    ; 2
  209.         > (define msg "Hello world!\n")                                 
  210.         "Hello world!\n"
  211.         > (call vio-wrt-tty msg (word (length msg)) (word 0))       ; 3
  212.         Hello world!
  213.                     0                                               ; 4
  214.                     
  215.     In line 1, we defined a variable called VIO-WRT-TTY (we could
  216. have called it BINKY if we wanted, or FIDO) that contains a function
  217. pointer to the OS/2 VioWrtTTy function.  The (getprocaddr) function
  218. takes a handle to a dynamic-link library (like VIOCALLS.DLL) and an
  219. ASCII string naming a function presumably in that DLL.  The major
  220. OS/2 DLL's are pre-loaded in the file INIT.LSP using the (loadmodule)
  221. function.  The (getprocaddr) function returned a function pointer to
  222. VioWrtTTy: that's 15142831 in line 2.  If we wanted to see a more
  223. sensible hexadecimal display, we could say:
  224.  
  225.         > (ultoa vio-wrt-tty 16)        ; display it in base 16
  226.         "E70FAF"
  227.  
  228. or we could set the XLISP global variable *integer-format* with a printf()
  229. mask:
  230.  
  231.         > (define *integer-format* "%Fp")
  232.         "%Fp"
  233.         > vio-wrt-tty
  234.         00E7:0FAF
  235.         > (define *integer-format* "%lu")   ; change it back
  236.         "%lu"
  237.     
  238.     In line 3, we actually call this function, using the OS2XLISP
  239. (call) function, which takes a variable number of variable-typed
  240. arguments.  Because XLISP numbers are longs (4 bytes) by default, and
  241. since the VioWrtTTy function expects words (2 bytes), we had to
  242. "cast" the arguments with the (word) function.  The VioWrtTTy
  243. function printed out "Hello world!\n" and returned control to
  244. OS2XLISP.  Because the function succeeded, OS2XLISP printed out 0
  245. (the OS/2 convention for "no error").
  246.  
  247.     There's plenty more we could do with this one example.  For instance,
  248. what was that address we got back from (getprocaddr)?
  249.  
  250.         > (lar (fp-seg vio-wrt-tty))            ; access rights byte
  251.         251
  252.         > (code? (fp-seg vio-wrt-tty))          ; see INIT.LSP
  253.         T
  254.         > (lsl (fp-seg vio-wrt-tty))            ; segment size
  255.         11306
  256.  
  257.     In a more practical vein, note that it would be a royal pain to 
  258. have to specify the arguments to VioWrtTTy like this all the time.  So
  259. we can write a Lisp function to handle all the arguments for us:
  260.  
  261.         > (define (vio-wrt-tty msg)
  262.             (call vio-wrt-tty msg (word (length msg)) (word 0) T))
  263.         VIO-WRT-TTY
  264.         > (vio-wrt-tty "Testing, testing")
  265.         Testing, testing
  266.                         T
  267.                             
  268.     The (define) macro can be used to create functions just as easily
  269. as it can be used to create variables.  Now, (vrt-wrt-tty) can be used
  270. as if it came "built in" to OS2XLISP.  Also, note the T we put in
  271. as the last argument to (call):  this is a "retval directive" which means
  272. that the (call) function should interpret a 0 returned from the OS/2
  273. function as meaning success (in Lisp, T means true and NIL means false).
  274.  
  275.     Many OS/2 functions require a pointer to memory, which the OS/2
  276. function will fill with data:
  277.  
  278.         > (define gdt 0)
  279.         0
  280.         > (define ldt 0)
  281.         0
  282.         > (call                                                 
  283.             (getprocaddr doscalls "DOSGETINFOSEG")
  284.             ^gdt ^ldt t)
  285.         T
  286.         > gdt
  287.         96
  288.         > ldt
  289.         15
  290.             
  291.     Notice that we didn't bother creating a variable for the function
  292. pointer to DosGetInfoSeg, since we knew we were just using it once.  Since
  293. we wanted to pass pointers to the variables to OS/2, we prefaced them 
  294. with the ^ macro-character, which is short-hand for the (addr) function.
  295. After the call, the variables are no longer zero -- OS/2 has changed these
  296. Lisp variables, right out from under OS2XLISP's nose!
  297.  
  298.     Users of previous versions of OS2XLISP:  note that you no longer
  299. need to use ordinal numbers (yuk!) to retrieve functions from the DOSCALLS
  300. dynamic-link library:  ASCII names are okay now.
  301.  
  302.     What can we do with these information segments?  One example is
  303. determining our process id (PID).  This information is kept in the 
  304. first two bytes of the local information segment:
  305.     
  306.         > (peek (mk-fp ldt 0) 'int)
  307.         11
  308.             
  309. The 'int is another "retval directive", by the way.
  310.  
  311.     If we thought we were going to be interrogating this value a lot, we
  312. could bury the details of the (peek) in a function that take no arguments:
  313.             
  314.         > (define (getpid)
  315.             (peek (mk-fp ldt 0) 'int))
  316.         GETPID
  317.         > (getpid)
  318.         11
  319.             
  320.     Of course, this value will never change during the life of the
  321. process.  An example of a value that would change is the foreground
  322. flag, kept in the int at offset 12 in the local information segment;
  323. anything non-zero means the process is running in the foreground:
  324.  
  325.         > (peek (mk-fp ldt 12) 'int)
  326.         65535
  327.         > (define (foreground?)
  328.             (not (zerop (peek (mk-fp ldt 12) 'int))))
  329.         FOREGROUND?
  330.         > (foreground?)
  331.         T
  332.             
  333.     Since we're typing expressions right into OS2XLISP, naturally
  334. (foreground?) is going to return true!  Let's exercise this function a 
  335. little:
  336.  
  337.         > (dotimes
  338.             (i 1000)
  339.             (princ (foreground?)))
  340.         
  341. Now, toggle in and out of OS2XLISP with Alt-Esc (I'm assuming that
  342. you're running OS2XLISP is one session, and reading this documentation
  343. in another protected-mode session):  while OS2XLISP is in the
  344. foreground, T is printed out, while it's churning away in the background,
  345. it prints out NIL (which you'll see when you switch back in).  This
  346. loop runs for 1,000 iterations and then stops.  If you get tired of
  347. watching it, hit ^C, then ^Z to get out of the debugger.
  348.  
  349.     Finally: see the file STRUCT.LSP for examples of how to use
  350. structures in OS/2 API calls, and how to convert between OS/2
  351. structures and Lisp lists using (make-struct) and (unpack-struct).
  352.  
  353.  
  354. 5) *** C FUNCTION CALLS FROM OS2XLISP ***
  355.  
  356.     The same mechanism that lets OS2XLISP make OS/2 function calls, also
  357. lets you Lisp programs make C run-time library calls.  Well, almost the
  358. same mechanism:  Since the OS/2 API uses the Pascal function calling
  359. convention (which, by the way, has almost nothing to do with the Pascal
  360. programming language), we need a separate gateway for dynamic-link
  361. functions using the C calling convention:
  362.  
  363.         > (define printf (getprocaddr crtlib "_printf"))
  364.         120000664
  365.         > (c-call printf "hello world!\n")
  366.         hello world!
  367.         13
  368.             
  369.     (getprocaddr), it should be noted, is cAsE _sEnSitivE!  Functions
  370. using the C calling convention should be presented in lower-case, with
  371. a leading underscore.  Note that we invoked printf with the (c-call)
  372. function, rather than with (call).  Also note that in this case, the
  373. function does not use the 0=T non-zero=NIL convention of the OS/2 API
  374. return values.  The 13 returned by printf happens to be the number of
  375. characters it printed out (including the newline).
  376.  
  377.     Again, we can create Lisp functions to take care of the details of
  378. (c-call) for us.  In the case of printf, sprintf, fprintf, and the like,
  379. it's a little trickier because of the variable number of arguments:
  380.  
  381.         > (defmacro printf (mask &rest ,@args)
  382.             `(c-call printf ,mask ,@args))
  383.         PRINTF
  384.         > (printf "printf lives at %Fp\n" printf)
  385.         printf lives at 02AF:3F76
  386.         26
  387.         > (printf "testing, testing, %u %lu %f\n" (word 1) 2 3.0)
  388.         testing, testing, 1 2 3.000000
  389.         31
  390.             
  391.     The two strange-looking lines of Lisp do all the work of passing
  392. a variable number of variable typed arguments to (c-call) which then
  393. passes them to the C run-time library (CRTLIB.DLL).
  394.  
  395.     We can call (printf) as though it were a built-in Lisp function!
  396. Thus, run-time dynamic linking immediately solves the problem of
  397. "mixed language programming" in the cleanest possible way.  It's also
  398. significant that we latched onto printf() by passing in an its name 
  399. as an ASCII string -- nothing magical or mysterious about ASCII
  400. strings!  This aspect of run-time dynamic linking resembles "string
  401. invocation" in certain high-level programming languages like ICON.
  402.  
  403.     The "retval directives" we've been mentioning really become
  404. important when making run-time dynamic links to the C standard
  405. library.  Unlike the OS/2 API functions, all of which return a
  406. two-byte error code, the C run-time functions return all sorts of
  407. values.  Here's an example of the 'str retval directive:
  408.  
  409.         > (define strtok (getprocaddr crtlib "_strtok"))
  410.         120024620
  411.         > (define (strtok string delims)
  412.             (c-call strtok string delims 'str))
  413.         STRTOK
  414.         > (strtok "this is a test"  " ")
  415.         "this"
  416.         > (strtok 0  " ")
  417.         "is"
  418.  
  419. We told (c-call) to return us a string (which, by the way, should be
  420. distinguished from a pointer to a string).
  421.  
  422.  
  423. 6) *** QUICK SUMMARY OF SOME OS/2-SPECIFIC FUNCTIONS ***
  424.  
  425. (loadmodule <name>) -- returns handle to dynamic-link library
  426. (getprocaddr <dll> <proc>) -- returns function pointer to DLL routine
  427. (freemodule <dll>) -- releases handle to DLL (hardly ever used)
  428.  
  429. (call <procaddr> [args...] [retval directive]) -- call dynamic-link routine
  430. (c-call <procaddr> [args...] [retval directive]) -- same, for C calling conv
  431. (math-call <procaddr> [args...]) -- for calling floating-point DLL routines
  432.  
  433. (os2-error) -- returns latest error code from above functions
  434.  
  435. (mk-fp <seg> <off>) -- make far pointer from segment/selector and offset
  436. (fp-seg <fp>) -- extract segment/selector from far pointer
  437. (fp-off <fp>) -- extract offset from far pointer
  438.  
  439. (word <n>) -- convert n to 2-byte quantity (word)
  440. ~n -- macro character for (word)
  441.  
  442. (lar <seg>) -- access rights byte for segment
  443. (lsl <seg>) -- limit (size) of segment
  444. (verr <seg>) -- verify reading rights to segment
  445. (verw <seg>) -- verify writing rights to segment
  446. (smsw) -- machine status word
  447. (ds), (ss), (sp), (flags) -- what you'ld expect
  448.  
  449. (addr <node>) -- get pointer to OS2XLISP data object
  450. ^node -- macro character for (addr)
  451.  
  452. (peek <fp> [retval directive]) -- examine byte, word, long, double, or string
  453. (poke <fp> <value> [retval directive]) -- poke in byte, word, long, dbl or str
  454.  
  455. (make-struct <template> [data]) -- returns OS/2-compatible packed structure
  456. (unpack-struct <template> <structure>) -- return Lisp list from OS/2 structure
  457.  
  458. (enum-procs <dll>) -- enumerate functions exported from dynamic link library
  459.  
  460.  
  461. 7) *** A FINAL NOTE ***
  462.  
  463.     If you have the C and ASM source code for OS2XLISP, you might note that
  464. the MAKE file does not make one thing perfectly clear:  your include 
  465. files have to come from \MSC\INC\MT rather than from plain old \MSC\INC.
  466. If you don't know what \MSC\INC\MT is, you'll have to get Microsoft C 5.1
  467. and check out the file MTDYNA.DOC.
  468.